#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <queue>
 
template <typename T> // 线程安全的阻塞队列
class BlockQueue{
public:
    BlockQueue(size_t cap): _cap(cap)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_nonfull, nullptr);
        pthread_cond_init(&_nonempty, nullptr);
    }
 
    // 生产者：当队列不满的时候添加数据
    void Push(const T& item)
    {
        pthread_mutex_lock(&_mutex);
        while(_q.size() >= _cap){
            // 队列数据已满，等待队列不满的信号
            pthread_cond_wait(&_nonfull, &_mutex);
        }
        _q.push(item);
        std::cout << "Produced: " << item << std::endl;
        // 通知消费者队列不为空
        pthread_cond_signal(&_nonempty);
        pthread_mutex_unlock(&_mutex);
    }
 
    // 消费者：当队列不为空的时候取出数据
    T Pop()
    {
        pthread_mutex_lock(&_mutex);
        while(_q.empty()){
            // 队列为空，等待队列不空的信号
            pthread_cond_wait(&_nonempty, &_mutex);
        }
        T item = _q.front();
        _q.pop();
        std::cout << "Consumed: " << item << std::endl;
        // 通知消费者队列不为空
        pthread_cond_signal(&_nonfull);
        pthread_mutex_unlock(&_mutex);
        return item;
    }
 
 
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_nonfull);
        pthread_cond_destroy(&_nonempty);
    }
 
private:   
    std::queue<T> _q;           // 队列
    size_t _cap;                // 最大容量
    pthread_mutex_t _mutex;
    pthread_cond_t _nonfull;    // 队列不满的条件变量
    pthread_cond_t _nonempty;   // 队列不空的条件变量
};
 
 
 
void *producer(void *args) { // 生产者线程函数
    BlockQueue<int> *q = static_cast<BlockQueue<int>*>(args);
    for(int i = 1; i <= 7; i++){
        q->Push(i); // 生产数据
        sleep(1);
    }
    return nullptr;
}
 
void *consumer(void *args){ // 消费者线程函数
    BlockQueue<int> *q = static_cast<BlockQueue<int>*>(args);
    for(int i = 1; i <= 7; i++){
        int item = q->Pop();    // 消费数据
        sleep(2);               
    }
    return nullptr;
}
 
int main()
{
    BlockQueue<int> q(3); // 创建一个容量为 3 的阻塞队列
 
    pthread_t producer_thread, consumer_thread;
    pthread_create(&producer_thread, nullptr, producer, &q);
    pthread_create(&consumer_thread, nullptr, consumer, &q);
 
    pthread_join(producer_thread, nullptr);
    pthread_join(consumer_thread, nullptr);
 
    return 0;
}